iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
自我挑戰組

Java SE系列 第 22

Day22:歐印萬

  • 分享至 

  • xImage
  •  

在尚未出現java.util.concurrent套件以前,多執行緒的程式都需要自己設計wait(), notify(), notifyAll()等程序,一個設計不良還可能造成死結(deadlock)的狀況。

在JDK5以後,就可以使用現成的java.util.concurrent套件來更便利的撰寫多執行緒相關程式。

  • Lock

Lock介面常用的實作類別為ReentrantLock,可以透過呼叫lock()方法讓執行緒取得鎖,並以呼叫unlock()來釋放鎖:

private Lock lock = new ReentrantLock();
private Object[] array;
private int next;
public void add(E e){
    lock.lock();
    try{
        if(next == array.length){
            array = Arrays.copyOf(array, array.length * 2);
        }
        array[next++] = e;
    }finally{
        lock.unlock();
    }
}

除了基本的lock()以及unlock(),還有tryLock()方法,傳回boolean,true表示可以取得鎖,有了這個方法,原先產生死結的程式就可以透過呼叫tryLock()來解開死結。

  • ReadWriteLock (ReentrantReadWriteLock)

由於寫入動作是產生多執行緒資料混亂的罪魁禍首,若讓其他讀取的動作也都進行同樣的鎖定程序,會導致效能低下,這時就可以用ReadWriteLock來增進程式的效能。

其原理為,讀取動作使用readLock()來進行鎖定,寫入動作使用writeLock()來進行鎖定。

當有執行緒企圖取得readLock時,只要物件的writeLock沒有被取走,那就可以被拿走;
當有執行緒企圖取得writeLock時,條件不只是writeLock沒有被取走,連readLock也沒有被取走時,才能允許執行緒取得writeLock。

  • ReadWriteLock (StampLock)

上述的ReentrantReadWriteLock實作是比較嚴謹的執行緒鎖定管控了,因為只要有任何執行緒再進行寫入動作,也不能夠讀取,稱為悲觀讀取(Pessimistic Reading)。假若我們的程式不需要這麼嚴格的管控呢?縱使被讀取的物件狀態會和真實狀態不一樣,但我們知道誤差不會太大抑或是有誤差我們無所謂,那就可以改用StampLock的實作類別。

long stamp = stampLock.tryOptimisticRead();
int num = array[i];
if(!stampLock.validate(stamp)){
    stamp = stampLock.readLock();
    try{
        num = array[i];
    }finally{
        stampLock.unlockRead(stamp);
    }
}
return num;
  • Condition

Condition的作用就是可以擁有不只一個物件的執行緒等待集,原生物件的wait(), notify()會共用該物件的等待集,所以不管執行緒原本是預備執行什麼動作,只要被叫進等待集,就是統一等待叫號;運用Condition物件的話,就可以依據需求將執行緒放進不同的等待集,當當前執行緒完成動作要教下一個來執行的時候,可以精準呼叫出該流程等待集中的執行緒,減少整體程式呼叫到無用執行緒的效能。

private Lock lock = new ReentrantLock();
private Condition aCondition = lock.newCondition();
private Condition bCondition = lock.newCondition();
public void aMethod(){
    lock.lock()
    try{
        isAOk();
        doSomething();
        bCondition.signal();  //相當於Object的notify()
    }finally{
        lock.unlock()
    }
}
public void isAOk(){
    if( someCondition() ){
        aCondition.await();  //相當於Object的wait()
    }
}
public void bMethod(){
    lock.lock()
    try{
        isBOk();
        doSomething();
        aCondition.signal();
    }finally{
        lock.unlock()
    }
}
public void isBOk(){
    if( someCondition() ){
        bCondition.await();
    }
}

上一篇
Day21:人生跑馬燈
下一篇
Day23:交給專業的來
系列文
Java SE30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言